﻿using System.IO.Compression;
using System.Reflection;
using System.Runtime.Loader;
using Launcher;
using LiteDB;

var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Launcher.BuildTest");

using var database = new LiteDatabase(stream);

// 接管未找到的程序集处理
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
    try
    {
        var name = eventArgs.Name.Split(",")[0];
        if (!name.EndsWith(".dll"))
        {
            name += ".dll";
        }

        var file = database!.FileStorage.Find(x => x.Filename == name).FirstOrDefault();

        using var memoryStream = new MemoryStream();
        file?.OpenRead().CopyToAsync(memoryStream);

        return file != null ? Assembly.Load(memoryStream.ToArray()) : default;
    }
    catch (Exception)
    {
        return default;
    }
};

var main = database.GetCollection<MainAssembly>();

var mainAssembly = main.Find(x => true).First();

// 最好是一开始加载好所有程序集，这里还可以优化
foreach (var fileInfo in database.FileStorage.FindAll().Where(x => x.Filename.EndsWith(".dll")))
{
    try
    {
        using var memory = new MemoryStream();
        fileInfo?.CopyTo(memory);
        memory.Position = 0; // Reset the position to the beginning of the stream
        using var decompressedMemory = new MemoryStream();
        await using (var gzip = new GZipStream(memory, CompressionMode.Decompress))
        {
            gzip.CopyTo(decompressedMemory);
        }

        try
        {
            decompressedMemory.Position = 0;
            AssemblyLoadContext.Default.LoadFromStream(decompressedMemory);
        }
        catch (Exception e)
        {
            try
            {
                // 有些native需要解压到当前目录所以这里需要处理一下
                await using var file = new FileStream(
                    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileInfo.Filename),
                    FileMode.OpenOrCreate, FileAccess.Write);
                decompressedMemory.Position = 0;
                await decompressedMemory.CopyToAsync(file);
                await file.FlushAsync();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}

// 通过配置获取到主程序的Stream
var mainFileStream = database.FileStorage.Find(x => x.Id == mainAssembly.Id).FirstOrDefault();

using var memoryStream = new MemoryStream();
mainFileStream?.CopyTo(memoryStream);

memoryStream.Position = 0;
using var decompressed = new MemoryStream();
await using (var gzip = new GZipStream(memoryStream, CompressionMode.Decompress))
{
    gzip.CopyTo(decompressed);
}

var assembly = Assembly.Load(decompressed.ToArray());

var entryPoint = EntryPointDiscoverer.FindStaticEntryMethod(assembly);

try
{
    var parameters = entryPoint.GetParameters();
    if (parameters.Length != 0)
    {
        var parameterValues = parameters.Select(p =>
                p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null)
            .ToArray();
        entryPoint.Invoke(null, parameterValues);
    }
    else
    {
        entryPoint.Invoke(null, null);
    }
}
catch (Exception e)
{
    Console.WriteLine(e);
}